home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Resources / Developers / XAMPP 1.5.4 / Windows installer / xampp-win32-1.5.4-installer.exe / xampp / php / pear / PEAR / Dependency2.php < prev    next >
Encoding:
PHP Script  |  2005-12-02  |  48.2 KB  |  1,195 lines

  1. <?php
  2. /**
  3.  * PEAR_Dependency2, advanced dependency validation
  4.  *
  5.  * PHP versions 4 and 5
  6.  *
  7.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  8.  * that is available through the world-wide-web at the following URI:
  9.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  10.  * the PHP License and are unable to obtain it through the web, please
  11.  * send a note to license@php.net so we can mail you a copy immediately.
  12.  *
  13.  * @category   pear
  14.  * @package    PEAR
  15.  * @author     Greg Beaver <cellog@php.net>
  16.  * @copyright  1997-2005 The PHP Group
  17.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  18.  * @version    CVS: $Id: Dependency2.php,v 1.48 2005/10/29 21:23:19 cellog Exp $
  19.  * @link       http://pear.php.net/package/PEAR
  20.  * @since      File available since Release 1.4.0a1
  21.  */
  22.  
  23. /**
  24.  * Required for the PEAR_VALIDATE_* constants
  25.  */
  26. require_once 'PEAR/Validate.php';
  27.  
  28. /**
  29.  * Dependency check for PEAR packages
  30.  *
  31.  * This class handles both version 1.0 and 2.0 dependencies
  32.  * WARNING: *any* changes to this class must be duplicated in the
  33.  * test_PEAR_Dependency2 class found in tests/PEAR_Dependency2/setup.php.inc,
  34.  * or unit tests will not actually validate the changes
  35.  * @category   pear
  36.  * @package    PEAR
  37.  * @author     Greg Beaver <cellog@php.net>
  38.  * @copyright  1997-2005 The PHP Group
  39.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  40.  * @version    Release: 1.4.5
  41.  * @link       http://pear.php.net/package/PEAR
  42.  * @since      Class available since Release 1.4.0a1
  43.  */
  44. class PEAR_Dependency2
  45. {
  46.     /**
  47.      * One of the PEAR_VALIDATE_* states
  48.      * @see PEAR_VALIDATE_NORMAL
  49.      * @var integer
  50.      */
  51.     var $_state;
  52.     /**
  53.      * Command-line options to install/upgrade/uninstall commands
  54.      * @param array
  55.      */
  56.     var $_options;
  57.     /**
  58.      * @var OS_Guess
  59.      */
  60.     var $_os;
  61.     /**
  62.      * @var PEAR_Registry
  63.      */
  64.     var $_registry;
  65.     /**
  66.      * @var PEAR_Config
  67.      */
  68.     var $_config;
  69.     /**
  70.      * @var PEAR_DependencyDB
  71.      */
  72.     var $_dependencydb;
  73.     /**
  74.      * Output of PEAR_Registry::parsedPackageName()
  75.      * @var array
  76.      */
  77.     var $_currentPackage;
  78.     /**
  79.      * @param PEAR_Config
  80.      * @param array installation options
  81.      * @param array format of PEAR_Registry::parsedPackageName()
  82.      * @param int installation state (one of PEAR_VALIDATE_*)
  83.      */
  84.     function PEAR_Dependency2(&$config, $installoptions, $package,
  85.                               $state = PEAR_VALIDATE_INSTALLING)
  86.     {
  87.         $this->_config = &$config;
  88.         $this->_registry = &$config->getRegistry();
  89.         if (!class_exists('PEAR_DependencyDB')) {
  90.             require_once 'PEAR/DependencyDB.php';
  91.         }
  92.         $this->_dependencydb = &PEAR_DependencyDB::singleton($config);
  93.         $this->_options = $installoptions;
  94.         $this->_state = $state;
  95.         if (!class_exists('OS_Guess')) {
  96.             require_once 'OS/Guess.php';
  97.         }
  98.         $this->_os = new OS_Guess;
  99.         $this->_currentPackage = $package;
  100.     }
  101.  
  102.     function _getExtraString($dep)
  103.     {
  104.         $extra = ' (';
  105.         if (isset($dep['uri'])) {
  106.             return '';
  107.         }
  108.         if (isset($dep['recommended'])) {
  109.             $extra .= 'recommended version ' . $dep['recommended'];
  110.         } else {
  111.             if (isset($dep['min'])) {
  112.                 $extra .= 'version >= ' . $dep['min'];
  113.             }
  114.             if (isset($dep['max'])) {
  115.                 if ($extra != ' (') {
  116.                     $extra .= ', ';
  117.                 }
  118.                 $extra .= 'version <= ' . $dep['max'];
  119.             }
  120.             if (isset($dep['exclude'])) {
  121.                 if (!is_array($dep['exclude'])) {
  122.                     $dep['exclude'] = array($dep['exclude']);
  123.                 }
  124.                 if ($extra != ' (') {
  125.                     $extra .= ', ';
  126.                 }
  127.                 $extra .= 'excluded versions: ';
  128.                 foreach ($dep['exclude'] as $i => $exclude) {
  129.                     if ($i) {
  130.                         $extra .= ', ';
  131.                     }
  132.                     $extra .= $exclude;
  133.                 }
  134.             }
  135.         }
  136.         $extra .= ')';
  137.         if ($extra == ' ()') {
  138.             $extra = '';
  139.         }
  140.         return $extra;
  141.     }
  142.  
  143.     /**
  144.      * This makes unit-testing a heck of a lot easier
  145.      */
  146.     function getPHP_OS()
  147.     {
  148.         return PHP_OS;
  149.     }
  150.  
  151.     /**
  152.      * This makes unit-testing a heck of a lot easier
  153.      */
  154.     function getsysname()
  155.     {
  156.         return $this->_os->getSysname();
  157.     }
  158.  
  159.     /**
  160.      * Specify a dependency on an OS.  Use arch for detailed os/processor information
  161.      *
  162.      * There are two generic OS dependencies that will be the most common, unix and windows.
  163.      * Other options are linux, freebsd, darwin (OS X), sunos, irix, hpux, aix
  164.      */
  165.     function validateOsDependency($dep)
  166.     {
  167.         if ($this->_state != PEAR_VALIDATE_INSTALLING &&
  168.               $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  169.             return true;
  170.         }
  171.         if (isset($dep['conflicts'])) {
  172.             $not = true;
  173.         } else {
  174.             $not = false;
  175.         }
  176.         if ($dep['name'] == '*') {
  177.             return true;
  178.         }
  179.         switch (strtolower($dep['name'])) {
  180.             case 'windows' :
  181.                 if ($not) {
  182.                     if (strtolower(substr($this->getPHP_OS(), 0, 3)) == 'win') {
  183.                         if (!isset($this->_options['nodeps']) &&
  184.                               !isset($this->_options['force'])) {
  185.                             return $this->raiseError("Cannot install %s on Windows");
  186.                         } else {
  187.                             return $this->warning("warning: Cannot install %s on Windows");
  188.                         }
  189.                     }
  190.                 } else {
  191.                     if (strtolower(substr($this->getPHP_OS(), 0, 3)) != 'win') {
  192.                         if (!isset($this->_options['nodeps']) &&
  193.                               !isset($this->_options['force'])) {
  194.                             return $this->raiseError("Can only install %s on Windows");
  195.                         } else {
  196.                             return $this->warning("warning: Can only install %s on Windows");
  197.                         }
  198.                     }
  199.                 }
  200.             break;
  201.             case 'unix' :
  202.                 $unices = array('linux', 'freebsd', 'darwin', 'sunos', 'irix', 'hpux', 'aix');
  203.                 if ($not) {
  204.                     if (in_array($this->getSysname(), $unices)) {
  205.                         if (!isset($this->_options['nodeps']) &&
  206.                               !isset($this->_options['force'])) {
  207.                             return $this->raiseError("Cannot install %s on any Unix system");
  208.                         } else {
  209.                             return $this->warning(
  210.                                 "warning: Cannot install %s on any Unix system");
  211.                         }
  212.                     }
  213.                 } else {
  214.                     if (!in_array($this->getSysname(), $unices)) {
  215.                         if (!isset($this->_options['nodeps']) &&
  216.                               !isset($this->_options['force'])) {
  217.                             return $this->raiseError("Can only install %s on a Unix system");
  218.                         } else {
  219.                             return $this->warning(
  220.                                 "warning: Can only install %s on a Unix system");
  221.                         }
  222.                     }
  223.                 }
  224.             break;
  225.             default :
  226.                 if ($not) {
  227.                     if (strtolower($dep['name']) == strtolower($this->getSysname())) {
  228.                         if (!isset($this->_options['nodeps']) &&
  229.                               !isset($this->_options['force'])) {
  230.                             return $this->raiseError('Cannot install %s on ' . $dep['name'] .
  231.                                 ' operating system');
  232.                         } else {
  233.                             return $this->warning('warning: Cannot install %s on ' .
  234.                                 $dep['name'] . ' operating system');
  235.                         }
  236.                     }
  237.                 } else {
  238.                     if (strtolower($dep['name']) != strtolower($this->getSysname())) {
  239.                         if (!isset($this->_options['nodeps']) &&
  240.                               !isset($this->_options['force'])) {
  241.                             return $this->raiseError('Cannot install %s on ' .
  242.                                 $this->getSysname() .
  243.                                 ' operating system, can only install on ' . $dep['name']);
  244.                         } else {
  245.                             return $this->warning('warning: Cannot install %s on ' .
  246.                                 $this->getSysname() .
  247.                                 ' operating system, can only install on ' . $dep['name']);
  248.                         }
  249.                     }
  250.                 }
  251.         }
  252.         return true;
  253.     }
  254.  
  255.     /**
  256.      * This makes unit-testing a heck of a lot easier
  257.      */
  258.     function matchSignature($pattern)
  259.     {
  260.         return $this->_os->matchSignature($pattern);
  261.     }
  262.  
  263.     /**
  264.      * Specify a complex dependency on an OS/processor/kernel version,
  265.      * Use OS for simple operating system dependency.
  266.      *
  267.      * This is the only dependency that accepts an eregable pattern.  The pattern
  268.      * will be matched against the php_uname() output parsed by OS_Guess
  269.      */
  270.     function validateArchDependency($dep)
  271.     {
  272.         if ($this->_state != PEAR_VALIDATE_INSTALLING) {
  273.             return true;
  274.         }
  275.         if (isset($dep['conflicts'])) {
  276.             $not = true;
  277.         } else {
  278.             $not = false;
  279.         }
  280.         if (!$this->matchSignature($dep['pattern'])) {
  281.             if (!$not) {
  282.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  283.                     return $this->raiseError('%s Architecture dependency failed, does not ' .
  284.                         'match "' . $dep['pattern'] . '"');
  285.                 } else {
  286.                     return $this->warning('warning: %s Architecture dependency failed, does ' .
  287.                         'not match "' . $dep['pattern'] . '"');
  288.                 }
  289.             }
  290.             return true;
  291.         } else {
  292.             if ($not) {
  293.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  294.                     return $this->raiseError('%s Architecture dependency failed, required "' .
  295.                         $dep['pattern'] . '"');
  296.                 } else {
  297.                     return $this->warning('warning: %s Architecture dependency failed, ' .
  298.                         'required "' . $dep['pattern'] . '"');
  299.                 }
  300.             }
  301.             return true;
  302.         }
  303.     }
  304.  
  305.     /**
  306.      * This makes unit-testing a heck of a lot easier
  307.      */
  308.     function extension_loaded($name)
  309.     {
  310.         return extension_loaded($name);
  311.     }
  312.  
  313.     /**
  314.      * This makes unit-testing a heck of a lot easier
  315.      */
  316.     function phpversion($name = null)
  317.     {
  318.         if ($name !== null) {
  319.             return phpversion($name);
  320.         } else {
  321.             return phpversion();
  322.         }
  323.     }
  324.  
  325.     function validateExtensionDependency($dep, $required = true)
  326.     {
  327.         if ($this->_state != PEAR_VALIDATE_INSTALLING &&
  328.               $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  329.             return true;
  330.         }
  331.         $loaded = $this->extension_loaded($dep['name']);
  332.         $extra = $this->_getExtraString($dep);
  333.         if (isset($dep['exclude'])) {
  334.             if (!is_array($dep['exclude'])) {
  335.                 $dep['exclude'] = array($dep['exclude']);
  336.             }
  337.         }
  338.         if (!isset($dep['min']) && !isset($dep['max']) &&
  339.               !isset($dep['recommended']) && !isset($dep['exclude'])) {
  340.             if ($loaded) {
  341.                 if (isset($dep['conflicts'])) {
  342.                     if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  343.                         return $this->raiseError('%s conflicts with PHP extension "' .
  344.                             $dep['name'] . '"' . $extra);
  345.                     } else {
  346.                         return $this->warning('warning: %s conflicts with PHP extension "' .
  347.                             $dep['name'] . '"' . $extra);
  348.                     }
  349.                 }
  350.                 return true;
  351.             } else {
  352.                 if (isset($dep['conflicts'])) {
  353.                     return true;
  354.                 }
  355.                 if ($required) {
  356.                     if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  357.                         return $this->raiseError('%s requires PHP extension "' .
  358.                             $dep['name'] . '"' . $extra);
  359.                     } else {
  360.                         return $this->warning('warning: %s requires PHP extension "' .
  361.                             $dep['name'] . '"' . $extra);
  362.                     }
  363.                 } else {
  364.                     return $this->warning('%s can optionally use PHP extension "' .
  365.                         $dep['name'] . '"' . $extra);
  366.                 }
  367.             }
  368.         }
  369.         if (!$loaded) {
  370.             if (isset($dep['conflicts'])) {
  371.                 return true;
  372.             }
  373.             if (!$required) {
  374.                 return $this->warning('%s can optionally use PHP extension "' .
  375.                     $dep['name'] . '"' . $extra);
  376.             } else {
  377.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  378.                     return $this->raiseError('%s requires PHP extension "' . $dep['name'] .
  379.                         '"' . $extra);
  380.                 }
  381.                     return $this->warning('warning: %s requires PHP extension "' . $dep['name'] .
  382.                         '"' . $extra);
  383.             }
  384.         }
  385.         $version = (string) $this->phpversion($dep['name']);
  386.         if (empty($version)) {
  387.             $version = '0';
  388.         }
  389.         $fail = false;
  390.         if (isset($dep['min'])) {
  391.             if (!version_compare($version, $dep['min'], '>=')) {
  392.                 $fail = true;
  393.             }
  394.         }
  395.         if (isset($dep['max'])) {
  396.             if (!version_compare($version, $dep['max'], '<=')) {
  397.                 $fail = true;
  398.             }
  399.         }
  400.         if ($fail && !isset($dep['conflicts'])) {
  401.             if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  402.                 return $this->raiseError('%s requires PHP extension "' . $dep['name'] .
  403.                     '"' . $extra . ', installed version is ' . $version);
  404.             } else {
  405.                 return $this->warning('warning: %s requires PHP extension "' . $dep['name'] .
  406.                     '"' . $extra . ', installed version is ' . $version);
  407.             }
  408.         } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && isset($dep['conflicts'])) {
  409.             if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  410.                 return $this->raiseError('%s conflicts with PHP extension "' .
  411.                     $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  412.             } else {
  413.                 return $this->warning('warning: %s conflicts with PHP extension "' .
  414.                     $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  415.             }
  416.         }
  417.         if (isset($dep['exclude'])) {
  418.             foreach ($dep['exclude'] as $exclude) {
  419.                 if (version_compare($version, $exclude, '==')) {
  420.                     if (isset($dep['conflicts'])) {
  421.                         continue;
  422.                     }
  423.                     if (!isset($this->_options['nodeps']) &&
  424.                           !isset($this->_options['force'])) {
  425.                         return $this->raiseError('%s is not compatible with PHP extension "' .
  426.                             $dep['name'] . '" version ' .
  427.                             $exclude);
  428.                     } else {
  429.                         return $this->warning('warning: %s is not compatible with PHP extension "' .
  430.                             $dep['name'] . '" version ' .
  431.                             $exclude);
  432.                     }
  433.                 } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) {
  434.                     if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  435.                         return $this->raiseError('%s conflicts with PHP extension "' .
  436.                             $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  437.                     } else {
  438.                         return $this->warning('warning: %s conflicts with PHP extension "' .
  439.                             $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  440.                     }
  441.                 }
  442.             }
  443.         }
  444.         if (isset($dep['recommended'])) {
  445.             if (version_compare($version, $dep['recommended'], '==')) {
  446.                 return true;
  447.             } else {
  448.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  449.                     return $this->raiseError('%s dependency: PHP extension ' . $dep['name'] .
  450.                         ' version "' . $version . '"' .
  451.                         ' is not the recommended version "' . $dep['recommended'] .
  452.                         '", but may be compatible, use --force to install');
  453.                 } else {
  454.                     return $this->warning('warning: %s dependency: PHP extension ' .
  455.                         $dep['name'] . ' version "' . $version . '"' .
  456.                         ' is not the recommended version "' . $dep['recommended'].'"');
  457.                 }
  458.             }
  459.         }
  460.         return true;
  461.     }
  462.  
  463.     function validatePhpDependency($dep)
  464.     {
  465.         if ($this->_state != PEAR_VALIDATE_INSTALLING &&
  466.               $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  467.             return true;
  468.         }
  469.         $version = $this->phpversion();
  470.         $extra = $this->_getExtraString($dep);
  471.         if (isset($dep['exclude'])) {
  472.             if (!is_array($dep['exclude'])) {
  473.                 $dep['exclude'] = array($dep['exclude']);
  474.             }
  475.         }
  476.         if (isset($dep['min'])) {
  477.             if (!version_compare($version, $dep['min'], '>=')) {
  478.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  479.                     return $this->raiseError('%s requires PHP' .
  480.                         $extra . ', installed version is ' . $version);
  481.                 } else {
  482.                     return $this->warning('warning: %s requires PHP' .
  483.                         $extra . ', installed version is ' . $version);
  484.                 }
  485.             }
  486.         }
  487.         if (isset($dep['max'])) {
  488.             if (!version_compare($version, $dep['max'], '<=')) {
  489.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  490.                     return $this->raiseError('%s requires PHP' .
  491.                         $extra . ', installed version is ' . $version);
  492.                 } else {
  493.                     return $this->warning('warning: %s requires PHP' .
  494.                         $extra . ', installed version is ' . $version);
  495.                 }
  496.             }
  497.         }
  498.         if (isset($dep['exclude'])) {
  499.             foreach ($dep['exclude'] as $exclude) {
  500.                 if (version_compare($version, $exclude, '==')) {
  501.                     if (!isset($this->_options['nodeps']) &&
  502.                           !isset($this->_options['force'])) {
  503.                         return $this->raiseError('%s is not compatible with PHP version ' .
  504.                             $exclude);
  505.                     } else {
  506.                         return $this->warning(
  507.                             'warning: %s is not compatible with PHP version ' .
  508.                             $exclude);
  509.                     }
  510.                 }
  511.             }
  512.         }
  513.         return true;
  514.     }
  515.  
  516.     /**
  517.      * This makes unit-testing a heck of a lot easier
  518.      */
  519.     function getPEARVersion()
  520.     {
  521.         return '1.4.5';
  522.     }
  523.  
  524.     function validatePearinstallerDependency($dep)
  525.     {
  526.         $pearversion = $this->getPEARVersion();
  527.         $extra = $this->_getExtraString($dep);
  528.         if (isset($dep['exclude'])) {
  529.             if (!is_array($dep['exclude'])) {
  530.                 $dep['exclude'] = array($dep['exclude']);
  531.             }
  532.         }
  533.         if (version_compare($pearversion, $dep['min'], '<')) {
  534.             if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  535.                 return $this->raiseError('%s requires PEAR Installer' . $extra .
  536.                     ', installed version is ' . $pearversion);
  537.             } else {
  538.                 return $this->warning('warning: %s requires PEAR Installer' . $extra .
  539.                     ', installed version is ' . $pearversion);
  540.             }
  541.         }
  542.         if (isset($dep['max'])) {
  543.             if (version_compare($pearversion, $dep['max'], '>')) {
  544.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  545.                     return $this->raiseError('%s requires PEAR Installer' . $extra .
  546.                         ', installed version is ' . $pearversion);
  547.                 } else {
  548.                     return $this->warning('warning: %s requires PEAR Installer' . $extra .
  549.                         ', installed version is ' . $pearversion);
  550.                 }
  551.             }
  552.         }
  553.         if (isset($dep['exclude'])) {
  554.             if (!isset($dep['exclude'][0])) {
  555.                 $dep['exclude'] = array($dep['exclude']);
  556.             }
  557.             foreach ($dep['exclude'] as $exclude) {
  558.                 if (version_compare($exclude, $pearversion, '==')) {
  559.                     if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  560.                         return $this->raiseError('%s is not compatible with PEAR Installer ' .
  561.                             'version ' . $exclude);
  562.                     } else {
  563.                         return $this->warning('warning: %s is not compatible with PEAR ' .
  564.                             'Installer version ' . $exclude);
  565.                     }
  566.                 }
  567.             }
  568.         }
  569.         return true;
  570.     }
  571.  
  572.     function validateSubpackageDependency($dep, $required, $params)
  573.     {
  574.         return $this->validatePackageDependency($dep, $required, $params);
  575.     }
  576.  
  577.     /**
  578.      * @param array dependency information (2.0 format)
  579.      * @param boolean whether this is a required dependency
  580.      * @param array a list of downloaded packages to be installed, if any
  581.      * @param boolean if true, then deps on pear.php.net that fail will also check
  582.      *                against pecl.php.net packages to accomodate extensions that have
  583.      *                moved to pecl.php.net from pear.php.net
  584.      */
  585.     function validatePackageDependency($dep, $required, $params, $depv1 = false)
  586.     {
  587.         if ($this->_state != PEAR_VALIDATE_INSTALLING &&
  588.               $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  589.             return true;
  590.         }
  591.         if (isset($dep['providesextension'])) {
  592.             if ($this->extension_loaded($dep['providesextension'])) {
  593.                 $save = $dep;
  594.                 $subdep = $dep;
  595.                 $subdep['name'] = $subdep['providesextension'];
  596.                 PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  597.                 $ret = $this->validateExtensionDependency($subdep, $required);
  598.                 PEAR::popErrorHandling();
  599.                 if (!PEAR::isError($ret)) {
  600.                     return true;
  601.                 }
  602.             }
  603.         }
  604.         if ($this->_state == PEAR_VALIDATE_INSTALLING) {
  605.             return $this->_validatePackageInstall($dep, $required, $depv1);
  606.         }
  607.         if ($this->_state == PEAR_VALIDATE_DOWNLOADING) {
  608.             return $this->_validatePackageDownload($dep, $required, $params, $depv1);
  609.         }
  610.     }
  611.  
  612.     function _validatePackageDownload($dep, $required, $params, $depv1 = false)
  613.     {
  614.         $dep['package'] = $dep['name'];
  615.         if (isset($dep['uri'])) {
  616.             $dep['channel'] = '__uri';
  617.         }
  618.         $depname = $this->_registry->parsedPackageNameToString($dep, true);
  619.         $found = false;
  620.         foreach ($params as $param) {
  621.             if ($param->isEqual(
  622.                   array('package' => $dep['name'],
  623.                         'channel' => $dep['channel']))) {
  624.                 $found = true;
  625.                 break;
  626.             }
  627.             if ($depv1 && $dep['channel'] == 'pear.php.net') {
  628.                 if ($param->isEqual(
  629.                   array('package' => $dep['name'],
  630.                         'channel' => 'pecl.php.net'))) {
  631.                     $found = true;
  632.                     break;
  633.                 }
  634.             }
  635.         }
  636.         if (!$found && isset($dep['providesextension'])) {
  637.             foreach ($params as $param) {
  638.                 if ($param->isExtension($dep['providesextension'])) {
  639.                     $found = true;
  640.                     break;
  641.                 }
  642.             }
  643.         }
  644.         if ($found) {
  645.             $version = $param->getVersion();
  646.             $installed = false;
  647.             $downloaded = true;
  648.         } else {
  649.             if ($this->_registry->packageExists($dep['name'], $dep['channel'])) {
  650.                 $installed = true;
  651.                 $downloaded = false;
  652.                 $version = $this->_registry->packageinfo($dep['name'], 'version',
  653.                     $dep['channel']);
  654.             } else {
  655.                 if ($dep['channel'] == 'pecl.php.net' && $this->_registry->packageExists($dep['name'],
  656.                       'pear.php.net')) {
  657.                     $installed = true;
  658.                     $downloaded = false;
  659.                     $version = $this->_registry->packageinfo($dep['name'], 'version',
  660.                         'pear.php.net');
  661.                 } else {
  662.                     $version = 'not installed or downloaded';
  663.                     $installed = false;
  664.                     $downloaded = false;
  665.                 }
  666.             }
  667.         }
  668.         $extra = $this->_getExtraString($dep);
  669.         if (isset($dep['exclude'])) {
  670.             if (!is_array($dep['exclude'])) {
  671.                 $dep['exclude'] = array($dep['exclude']);
  672.             }
  673.         }
  674.         if (!isset($dep['min']) && !isset($dep['max']) &&
  675.               !isset($dep['recommended']) && !isset($dep['exclude'])) {
  676.             if ($installed || $downloaded) {
  677.                 $installed = $installed ? 'installed' : 'downloaded';
  678.                 if (isset($dep['conflicts'])) {
  679.                     if ($version) {
  680.                         $rest = ", $installed version is " . $version;
  681.                     } else {
  682.                         $rest = '';
  683.                     }
  684.                     if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  685.                         return $this->raiseError('%s conflicts with package "' . $depname . '"' .
  686.                             $extra . $rest);
  687.                     } else {
  688.                         return $this->warning('warning: %s conflicts with package "' . $depname . '"' .
  689.                             $extra . $rest);
  690.                     }
  691.                 }
  692.                 return true;
  693.             } else {
  694.                 if (isset($dep['conflicts'])) {
  695.                     return true;
  696.                 }
  697.                 if ($required) {
  698.                     if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  699.                         return $this->raiseError('%s requires package "' . $depname . '"' .
  700.                             $extra);
  701.                     } else {
  702.                         return $this->warning('warning: %s requires package "' . $depname . '"' .
  703.                             $extra);
  704.                     }
  705.                 } else {
  706.                     return $this->warning('%s can optionally use package "' . $depname . '"' .
  707.                         $extra);
  708.                 }
  709.             }
  710.         }
  711.         if (!$installed && !$downloaded) {
  712.             if (isset($dep['conflicts'])) {
  713.                 return true;
  714.             }
  715.             if ($required) {
  716.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  717.                     return $this->raiseError('%s requires package "' . $depname . '"' .
  718.                         $extra);
  719.                 } else {
  720.                     return $this->warning('warning: %s requires package "' . $depname . '"' .
  721.                         $extra);
  722.                 }
  723.             } else {
  724.                 return $this->warning('%s can optionally use package "' . $depname . '"' .
  725.                     $extra);
  726.             }
  727.         }
  728.         $fail = false;
  729.         if (isset($dep['min'])) {
  730.             if (version_compare($version, $dep['min'], '<')) {
  731.                 $fail = true;
  732.             }
  733.         }
  734.         if (isset($dep['max'])) {
  735.             if (version_compare($version, $dep['max'], '>')) {
  736.                 $fail = true;
  737.             }
  738.         }
  739.         if ($fail && !isset($dep['conflicts'])) {
  740.             $installed = $installed ? 'installed' : 'downloaded';
  741.             $dep['package'] = $dep['name'];
  742.             $dep = $this->_registry->parsedPackageNameToString($dep, true);
  743.             if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  744.                 return $this->raiseError('%s requires package "' . $depname . '"' .
  745.                     $extra . ", $installed version is " . $version);
  746.             } else {
  747.                 return $this->warning('warning: %s requires package "' . $depname . '"' .
  748.                     $extra . ", $installed version is " . $version);
  749.             }
  750.         } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail &&
  751.               isset($dep['conflicts']) && !isset($dep['exclude'])) {
  752.             $installed = $installed ? 'installed' : 'downloaded';
  753.             if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  754.                 return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra .
  755.                     ", $installed version is " . $version);
  756.             } else {
  757.                 return $this->warning('warning: %s conflicts with package "' . $depname . '"' .
  758.                     $extra . ", $installed version is " . $version);
  759.             }
  760.         }
  761.         if (isset($dep['exclude'])) {
  762.             $installed = $installed ? 'installed' : 'downloaded';
  763.             foreach ($dep['exclude'] as $exclude) {
  764.                 if (version_compare($version, $exclude, '==') && !isset($dep['conflicts'])) {
  765.                     if (!isset($this->_options['nodeps']) &&
  766.                           !isset($this->_options['force'])) {
  767.                         return $this->raiseError('%s is not compatible with ' .
  768.                             $installed . ' package "' .
  769.                             $depname . '" version ' .
  770.                             $exclude);
  771.                     } else {
  772.                         return $this->warning('warning: %s is not compatible with ' .
  773.                             $installed . ' package "' .
  774.                             $depname . '" version ' .
  775.                             $exclude);
  776.                     }
  777.                 } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) {
  778.                     $installed = $installed ? 'installed' : 'downloaded';
  779.                     if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  780.                         return $this->raiseError('%s conflicts with package "' . $depname . '"' .
  781.                             $extra . ", $installed version is " . $version);
  782.                     } else {
  783.                         return $this->warning('warning: %s conflicts with package "' . $depname . '"' .
  784.                             $extra . ", $installed version is " . $version);
  785.                     }
  786.                 }
  787.             }
  788.         }
  789.         if (isset($dep['recommended'])) {
  790.             $installed = $installed ? 'installed' : 'downloaded';
  791.             if (version_compare($version, $dep['recommended'], '==')) {
  792.                 return true;
  793.             } else {
  794.                 if (!$found && $installed) {
  795.                     $param = $this->_registry->getPackage($dep['name'], $dep['channel']);
  796.                 }
  797.                 if ($param) {
  798.                     $found = false;
  799.                     foreach ($params as $parent) {
  800.                         if ($parent->isEqual($this->_currentPackage)) {
  801.                             $found = true;
  802.                             break;
  803.                         }
  804.                     }
  805.                     if ($found) {
  806.                         if ($param->isCompatible($parent)) {
  807.                             return true;
  808.                         }
  809.                     } else { // this is for validPackage() calls
  810.                         $parent = $this->_registry->getPackage($this->_currentPackage['package'],
  811.                             $this->_currentPackage['channel']);
  812.                         if ($parent !== null) {
  813.                             if ($param->isCompatible($parent)) {
  814.                                 return true;
  815.                             }
  816.                         }
  817.                     }
  818.                 }
  819.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force']) &&
  820.                       !isset($this->_options['loose'])) {
  821.                     return $this->raiseError('%s dependency package "' . $depname .
  822.                         '" ' . $installed . ' version ' . $version . 
  823.                         ' is not the recommended version ' . $dep['recommended'] .
  824.                         ', but may be compatible, use --force to install');
  825.                 } else {
  826.                     return $this->warning('warning: %s dependency package "' . $depname .
  827.                         '" ' . $installed . ' version ' . $version .
  828.                         ' is not the recommended version ' . $dep['recommended']);
  829.                 }
  830.             }
  831.         }
  832.         return true;
  833.     }
  834.  
  835.     function _validatePackageInstall($dep, $required, $depv1 = false)
  836.     {
  837.         return $this->_validatePackageDownload($dep, $required, array(), $depv1);
  838.     }
  839.  
  840.     /**
  841.      * Verify that uninstalling packages passed in to command line is OK.
  842.      *
  843.      * @param PEAR_Installer $dl
  844.      * @return PEAR_Error|true
  845.      */
  846.     function validatePackageUninstall(&$dl)
  847.     {
  848.         if (PEAR::isError($this->_dependencydb)) {
  849.             return $this->_dependencydb;
  850.         }
  851.         $params = array();
  852.         // construct an array of "downloaded" packages to fool the package dependency checker
  853.         // into using these to validate uninstalls of circular dependencies
  854.         $downloaded = &$dl->getUninstallPackages();
  855.         foreach ($downloaded as $i => $pf) {
  856.             if (!class_exists('PEAR_Downloader_Package')) {
  857.                 require_once 'PEAR/Downloader/Package.php';
  858.             }
  859.             $dp = &new PEAR_Downloader_Package($dl);
  860.             $dp->setPackageFile($downloaded[$i]);
  861.             $params[$i] = &$dp;
  862.         }
  863.         $deps = $this->_dependencydb->getDependentPackageDependencies($this->_currentPackage);
  864.         $fail = false;
  865.         if ($deps) {
  866.             foreach ($deps as $channel => $info) {
  867.                 foreach ($info as $package => $ds) {
  868.                     foreach ($ds as $d) {
  869.                         $d['dep']['package'] = $d['dep']['name'];
  870.                         $checker = &new PEAR_Dependency2($this->_config, $this->_options,
  871.                             array('channel' => $channel, 'package' => $package), $this->_state);
  872.                         $dep = $d['dep'];
  873.                         $required = $d['type'] == 'required';
  874.                         $ret = $checker->_validatePackageUninstall($dep, $required, $params, $dl);
  875.                         if (is_array($ret)) {
  876.                             $dl->log(0, $ret[0]);
  877.                         } elseif (PEAR::isError($ret)) {
  878.                             $dl->log(0, $ret->getMessage());
  879.                             $fail = true;
  880.                         }
  881.                     }
  882.                 }
  883.             }
  884.         }
  885.         if ($fail) {
  886.             if (isset($this->_options['nodeps']) || isset($this->_options['force'])) {
  887.                 return $this->warning(
  888.                     'warning: %s should not be uninstalled, other installed packages depend ' .
  889.                     'on this package');
  890.             } else {
  891.                 return $this->raiseError(
  892.                     '%s cannot be uninstalled, other installed packages depend on this package');
  893.             }
  894.         }
  895.         return true;
  896.     }
  897.  
  898.     function _validatePackageUninstall($dep, $required, $params, &$dl)
  899.     {
  900.         $dep['package'] = $dep['name'];
  901.         $depname = $this->_registry->parsedPackageNameToString($dep, true);
  902.         $found = false;
  903.         foreach ($params as $param) {
  904.             if ($param->isEqual($this->_currentPackage)) {
  905.                 $found = true;
  906.                 break;
  907.             }
  908.         }
  909.         $version = $this->_registry->packageinfo($dep['name'], 'version',
  910.             $dep['channel']);
  911.         if (!$version) {
  912.             return true;
  913.         }
  914.         $extra = $this->_getExtraString($dep);
  915.         if (isset($dep['exclude'])) {
  916.             if (!is_array($dep['exclude'])) {
  917.                 $dep['exclude'] = array($dep['exclude']);
  918.             }
  919.         }
  920.         if (isset($dep['conflicts'])) {
  921.             return true; // uninstall OK - these packages conflict (probably installed with --force)
  922.         }
  923.         if (!isset($dep['min']) && !isset($dep['max'])) {
  924.             if ($required) {
  925.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  926.                     return $this->raiseError('%s' . $extra . ' is required by installed package "' .
  927.                         $depname . '"');
  928.                 } else {
  929.                     return $this->warning('warning: %s' . $extra .
  930.                         ' is required by installed package "' . $depname . '"');
  931.                 }
  932.             } else {
  933.                 return $this->warning('%s' . $extra .
  934.                     ' can be optionally used by installed package "' . $depname . '"');
  935.             }
  936.         }
  937.         $fail = false;
  938.         if (isset($dep['min'])) {
  939.             if (version_compare($version, $dep['min'], '>=')) {
  940.                 $fail = true;
  941.             }
  942.         }
  943.         if (isset($dep['max'])) {
  944.             if (version_compare($version, $dep['max'], '<=')) {
  945.                 $fail = true;
  946.             }
  947.         }
  948.         if ($fail) {
  949.             if ($found) {
  950.                 if (!isset($dl->___checked[$this->_currentPackage['channel']]
  951.                       [$this->_currentPackage['package']])) {
  952.                     $dl->___checked[$this->_currentPackage['channel']]
  953.                       [$this->_currentPackage['package']] = true;
  954.                     $deps = $this->_dependencydb->getDependentPackageDependencies(
  955.                         $this->_currentPackage);
  956.                     if ($deps) {
  957.                         foreach ($deps as $channel => $info) {
  958.                             foreach ($info as $package => $ds) {
  959.                                 foreach ($ds as $d) {
  960.                                     $d['dep']['package'] = $d['dep']['name'];
  961.                                     $checker = &new PEAR_Dependency2($this->_config, $this->_options,
  962.                                         array('channel' => $channel, 'package' => $package),
  963.                                         $this->_state);
  964.                                     $dep = $d['dep'];
  965.                                     $required = $d['type'] == 'required';
  966.                                     $ret = $checker->_validatePackageUninstall($dep, $required, $params,
  967.                                         $dl);
  968.                                     if (PEAR::isError($ret)) {
  969.                                         $fail = true;
  970.                                         break 3;
  971.                                     }
  972.                                 }
  973.                             }
  974.                             $fail = false;
  975.                         }
  976.                     }
  977.                 } else {
  978.                     return true;
  979.                 }
  980.             }
  981.             if (!$fail) {
  982.                 return true;
  983.             }
  984.             if ($required) {
  985.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  986.                     return $this->raiseError($depname . $extra . ' is required by installed package' .
  987.                         ' "%s"');
  988.                 } else {
  989.                     return $this->warning('warning: ' . $depname . $extra .
  990.                         ' is required by installed package "%s"');
  991.                 }
  992.             } else {
  993.                 return $this->warning($depname . $extra . ' can be optionally used by installed package' .
  994.                         ' "%s"');
  995.             }
  996.         }
  997.         return true;
  998.     }
  999.  
  1000.     /**
  1001.      * validate a downloaded package against installed packages
  1002.      * 
  1003.      * As of PEAR 1.4.3, this will only validate
  1004.      *
  1005.      * @param array|PEAR_Downloader_Package|PEAR_PackageFile_v1|PEAR_PackageFile_v2
  1006.      *              $pkg package identifier (either
  1007.      *                   array('package' => blah, 'channel' => blah) or an array with
  1008.      *                   index 'info' referencing an object)
  1009.      * @param PEAR_Downloader $dl
  1010.      * @param array $params full list of packages to install
  1011.      * @return true|PEAR_Error
  1012.      */
  1013.     function validatePackage($pkg, &$dl, $params = array())
  1014.     {
  1015.         if (is_array($pkg) && isset($pkg['info'])) {
  1016.             $deps = $this->_dependencydb->getDependentPackageDependencies($pkg['info']);
  1017.         } else {
  1018.             $deps = $this->_dependencydb->getDependentPackageDependencies($pkg);
  1019.         }
  1020.         $fail = false;
  1021.         if ($deps) {
  1022.             if (!class_exists('PEAR_Downloader_Package')) {
  1023.                 require_once 'PEAR/Downloader/Package.php';
  1024.             }
  1025.             $dp = &new PEAR_Downloader_Package($dl);
  1026.             if (is_object($pkg)) {
  1027.                 $dp->setPackageFile($pkg);
  1028.             } else {
  1029.                 $dp->setDownloadURL($pkg);
  1030.             }
  1031.             PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  1032.             foreach ($deps as $channel => $info) {
  1033.                 foreach ($info as $package => $ds) {
  1034.                     foreach ($params as $packd) {
  1035.                         if (strtolower($packd->getPackage()) == strtolower($package) &&
  1036.                               $packd->getChannel() == $channel) {
  1037.                             $dl->log(3, 'skipping installed package check of "' .
  1038.                                         $this->_registry->parsedPackageNameToString(
  1039.                                             array('channel' => $channel, 'package' => $package),
  1040.                                             true) .
  1041.                                         '", version "' . $packd->getVersion() . '" will be ' .
  1042.                                         'downloaded and installed');
  1043.                             continue 2; // jump to next package
  1044.                         }
  1045.                     }
  1046.                     foreach ($ds as $d) {
  1047.                         $checker = &new PEAR_Dependency2($this->_config, $this->_options,
  1048.                             array('channel' => $channel, 'package' => $package), $this->_state);
  1049.                         $dep = $d['dep'];
  1050.                         $required = $d['type'] == 'required';
  1051.                         $ret = $checker->_validatePackageDownload($dep, $required, array(&$dp));
  1052.                         if (is_array($ret)) {
  1053.                             $dl->log(0, $ret[0]);
  1054.                         } elseif (PEAR::isError($ret)) {
  1055.                             $dl->log(0, $ret->getMessage());
  1056.                             $fail = true;
  1057.                         }
  1058.                     }
  1059.                 }
  1060.             }
  1061.             PEAR::popErrorHandling();
  1062.         }
  1063.         if ($fail) {
  1064.             return $this->raiseError(
  1065.                 '%s cannot be installed, conflicts with installed packages');
  1066.         }
  1067.         return true;
  1068.     }
  1069.  
  1070.     /**
  1071.      * validate a package.xml 1.0 dependency
  1072.      */
  1073.     function validateDependency1($dep, $params = array())
  1074.     {
  1075.         if (!isset($dep['optional'])) {
  1076.             $dep['optional'] = 'no';
  1077.         }
  1078.         list($newdep, $type) = $this->normalizeDep($dep);
  1079.         if (!$newdep) {
  1080.             return $this->raiseError("Invalid Dependency");
  1081.         }
  1082.         if (method_exists($this, "validate{$type}Dependency")) {
  1083.             return $this->{"validate{$type}Dependency"}($newdep, $dep['optional'] == 'no',
  1084.                 $params, true);
  1085.         }
  1086.     }
  1087.  
  1088.     /**
  1089.      * Convert a 1.0 dep into a 2.0 dep
  1090.      */
  1091.     function normalizeDep($dep)
  1092.     {
  1093.         $types = array(
  1094.             'pkg' => 'Package',
  1095.             'ext' => 'Extension',
  1096.             'os' => 'Os',
  1097.             'php' => 'Php'
  1098.         );
  1099.         if (isset($types[$dep['type']])) {
  1100.             $type = $types[$dep['type']];
  1101.         } else {
  1102.             return array(false, false);
  1103.         }
  1104.         $newdep = array();
  1105.         switch ($type) {
  1106.             case 'Package' :
  1107.                 $newdep['channel'] = 'pear.php.net';
  1108.             case 'Extension' :
  1109.             case 'Os' :
  1110.                 $newdep['name'] = $dep['name'];
  1111.             break;
  1112.         }
  1113.         $dep['rel'] = PEAR_Dependency2::signOperator($dep['rel']);
  1114.         switch ($dep['rel']) {
  1115.             case 'has' :
  1116.                 return array($newdep, $type);
  1117.             break;
  1118.             case 'not' :
  1119.                 $newdep['conflicts'] = true;
  1120.             break;
  1121.             case '>=' :
  1122.             case '>' :
  1123.                 $newdep['min'] = $dep['version'];
  1124.                 if ($dep['rel'] == '>') {
  1125.                     $newdep['exclude'] = $dep['version'];
  1126.                 }
  1127.             break;
  1128.             case '<=' :
  1129.             case '<' :
  1130.                 $newdep['max'] = $dep['version'];
  1131.                 if ($dep['rel'] == '<') {
  1132.                     $newdep['exclude'] = $dep['version'];
  1133.                 }
  1134.             break;
  1135.             case 'ne' :
  1136.             case '!=' :
  1137.                 $newdep['min'] = '0';
  1138.                 $newdep['max'] = '100000';
  1139.                 $newdep['exclude'] = $dep['version'];
  1140.             break;
  1141.             case '==' :
  1142.                 $newdep['min'] = $dep['version'];
  1143.                 $newdep['max'] = $dep['version'];
  1144.             break;
  1145.         }
  1146.         if ($type == 'Php') {
  1147.             if (!isset($newdep['min'])) {
  1148.                 $newdep['min'] = '4.2.0';
  1149.             }
  1150.             if (!isset($newdep['max'])) {
  1151.                 $newdep['max'] = '6.0.0';
  1152.             }
  1153.         }
  1154.         return array($newdep, $type);
  1155.     }
  1156.  
  1157.     /**
  1158.      * Converts text comparing operators to them sign equivalents
  1159.      *
  1160.      * Example: 'ge' to '>='
  1161.      *
  1162.      * @access public
  1163.      * @param  string Operator
  1164.      * @return string Sign equivalent
  1165.      */
  1166.     function signOperator($operator)
  1167.     {
  1168.         switch($operator) {
  1169.             case 'lt': return '<';
  1170.             case 'le': return '<=';
  1171.             case 'gt': return '>';
  1172.             case 'ge': return '>=';
  1173.             case 'eq': return '==';
  1174.             case 'ne': return '!=';
  1175.             default:
  1176.                 return $operator;
  1177.         }
  1178.     }
  1179.  
  1180.     function raiseError($msg)
  1181.     {
  1182.         if (isset($this->_options['ignore-errors'])) {
  1183.             return $this->warning($msg);
  1184.         }
  1185.         return PEAR::raiseError(sprintf($msg, $this->_registry->parsedPackageNameToString(
  1186.             $this->_currentPackage, true)));
  1187.     }
  1188.  
  1189.     function warning($msg)
  1190.     {
  1191.         return array(sprintf($msg, $this->_registry->parsedPackageNameToString(
  1192.             $this->_currentPackage, true)));
  1193.     }
  1194. }
  1195. ?>